﻿using Nest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace ES.Client.Filter
{
    public class BuilderFactory<T> where T : class
    {
        private string index;

        private string docType;

        private ElasticHub<T> elastic
        {
            get
            {
                return new ElasticHub<T>();
            }
        }

        internal BuilderFactory(string index, string docType)
        {
            this.index = index;
            this.docType = docType;
        }

        public IFilterBuilder GetBuilder(string field)
        {
            IFilterBuilder builder = null;
            var type = this.Adapter(field);
            switch (type)
            {
                case BuilderType.BasicField:
                    builder = new BasicFieldBuilder<T>(this.index, this.docType);
                    break;
                case BuilderType.RootNestedField:
                    builder = new RootNestedFieldBuilder<T>(this.index, this.docType);
                    break;
                case BuilderType.InnerNestedField:
                    builder = new InnerNestedFieldBuilder<T>(this.index, this.docType);
                    break;
                case BuilderType.RootObjectField:
                    builder = new RootObjectFieldBuilder<T>(this.index, this.docType);
                    break;
                case BuilderType.InnerObjectField:
                    builder = new InnerObjectFieldBuilder<T>(this.index, this.docType);
                    break;
                case BuilderType.Invalid:
                    builder = new InvalidBuilder<T>(this.index, this.docType);
                    break;
                default:
                    builder = new InvalidBuilder<T>(this.index, this.docType);
                    break;
            }

            return builder;
        }

        public IFilterBuilder GetBuilder(BuilderType type)
        {
            IFilterBuilder builder = null;
            switch (type)
            {
                case BuilderType.BasicField:
                    builder = new BasicFieldBuilder<T>(this.index, this.docType);
                    break;
                case BuilderType.RootNestedField:
                    builder = new RootNestedFieldBuilder<T>(this.index, this.docType);
                    break;
                case BuilderType.InnerNestedField:
                    builder = new InnerNestedFieldBuilder<T>(this.index, this.docType);
                    break;
                case BuilderType.RootObjectField:
                    builder = new RootObjectFieldBuilder<T>(this.index, this.docType);
                    break;
                case BuilderType.InnerObjectField:
                    builder = new InnerObjectFieldBuilder<T>(this.index, this.docType);
                    break;
                case BuilderType.Invalid:
                    builder = new InvalidBuilder<T>(this.index, this.docType);
                    break;
                default:
                    builder = new InvalidBuilder<T>(this.index, this.docType);
                    break;
            }

            return builder;
        }

        private BuilderType Adapter(string field)
        {
            if (string.IsNullOrWhiteSpace(field))
            {
                return BuilderType.Invalid;
            }

            if (field.EndsWith("."))
            {
                return BuilderType.Invalid;
            }

            if (field.IndexOf(".") > -1)
            {
                var _fields = field.Split(new char[1] { '.' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                var rootField = _fields.FirstOrDefault();

                if (elastic.IsNestedField(rootField))
                {
                    return BuilderType.InnerNestedField;
                }

                if (elastic.IsObjectField(rootField))
                {
                    return BuilderType.InnerObjectField;
                }
            }

            //var mapping = this.GetFieldMapping(field);
            //if (mapping == null)
            //{
            //    return BuilderType.Invalid;
            //}

            if (elastic.IsNestedField(field))
            {
                return BuilderType.RootNestedField;
            }

            if (elastic.IsObjectField(field))
            {
                return BuilderType.RootObjectField;
            }

            return BuilderType.BasicField;
        }
    }
}
